Categories
Vue 3

Vue 3 — Custom Events

Spread the love

Vue 3 is in beta and it’s subject to change.

Vue 3 is the up and coming version of Vue front end framework.

It builds on the popularity and ease of use of Vue 2.

In this article, we’ll look at how to emit and handle custom events with Vue 3.

Custom Events

We can emit custom events with the this.$emit method.

For example, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <component-a @increment-count="count++"></component-a>
      <p>{{count}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            count: 0
          };
        }
      });

      app.component("component-a", {
        template: `
          <div>
            <button @click='this.$emit("increment-count")'>click      me</button>
          </div>`
      });

      app.mount("#app");
    </script>
  </body>
</html>

We emit the increment-count event with the from component-a .

Then we listen to the same event within the parent Vue instance’s template with:

<component-a @increment-count="count++"></component-a>

The case of the event names have to be the same for this to work.

Therefore, when we click on the ‘click me’ button, we can increase the count by 1.

Defining Custom Events

We can define custom events with the emits option of a component.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <component-a @increment-count="count++"></component-a>
      <p>{{count}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            count: 0
          };
        }
      });

      app.component("component-a", {
        emits: ["increment-count"],
        template: `
          <div>
            <button @click='$emit("increment-count")'>click me</button>
          </div>`
      });

      app.mount("#app");
    </script>
  </body>
</html>

We have the emits option which has an array of event name strings that component-a can emit.

This serves as better documentation for our components since we can restrict the kinds of events that can be emitted.

Validate Emitted Events

We can add code to validate emitted events.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <component-a @increment-count="count += $event"></component-a>
      <p>{{count}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            count: 0
          };
        }
      });

      app.component("component-a", {
        emits: {
          ["increment-count"](value) {
            return value === 2;
          }
        },
        template: `
          <div>
            <button @click='$emit("increment-count", 2)'>click me</button>
          </div>`
      });

app.mount("#app");
    </script>
  </body>
</html>

to make sure that we always pass 2 into the $emit method.

We have the emits property in our component-a object with the increment-count method.

It takes the value parameter, which is the value that we passed in as the 2nd argument.

In the method, we return the validation result as a boolean.

If it’s valid, we return true .

Otherwise, we return false .

v-model arguments

v-model arguments can also be validated.

We can check the prop value with the props property.

For instance, we can write:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>App</title>
    <script src="https://unpkg.com/vue@next"></script>
  </head>
  <body>
    <div id="app">
      <component-a v-model:foo="bar"></component-a>
      <p>{{bar}}</p>
    </div>
    <script>
      const app = Vue.createApp({
        data() {
          return {
            bar: ""
          };
        }
      });

      app.component("component-a", {
        props: {
          foo: String
        },
        template: `
          <input
            type="text"
            :value="foo"
            @input="$emit('update:foo', $event.target.value)">
        `
      });

      app.mount("#app");
    </script>
  </body>
</html>

We have the props property, that has the key foo .

The value is String , so foo has to be a string.

Our input emits the update:foo event so we send the inputted value back to the parent component.

Then we can bind the parent’s property with the v-model:foo directive so that we can synchronize the value of foo with the value of the bar state.

Therefore, when we type into the input box, we’ll see the value that we entered displayed.

Conclusion

We can emit custom events by calling this.$emit with an event name and an optional 2nd argument with the value.

Then we can listen to it with the @ directive shorthand.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *